
#include <BFile>
#include <BStyle>
#include <BOpenGL>
#include <BHBoxLayout>
#include <BVBoxLayout>
#include <BLabel>
#include <BScrollBar>
#include <BKeyEvent>
#include <BMouseEvent>
#include <BSystem>
#include <BApplication>
#include <BXmlDocument>

#include "member_BScrollArea.h"
#include "member_BHtmlWidget.h"
#include "member_BHtmlItem.h"
#include "member_BXmlDocument.h"

using namespace BWE;

#define member					(*(member_BHtmlWidget*)_ptr)
#define member_allocate()		_ptr = new member_BHtmlWidget(this)
#define member_release()		delete (member_BHtmlWidget*)_ptr

BHtmlWidget::BHtmlWidget(BWidget* parent) : BScrollArea(parent)
{
	member_allocate();
	this->setAreaPolicy(Policy_Growing, Policy_Preferred);
}
BHtmlWidget::BHtmlWidget(const BString& title, BWidget* parent) : BScrollArea(title, parent)
{
	member_allocate();
	this->setAreaPolicy(Policy_Growing, Policy_Preferred);
}
BHtmlWidget::~BHtmlWidget()
{
	member_release();
}

bool BHtmlWidget::load(const BString& fileName)
{
	BXmlDocument xmldoc;
	if (!xmldoc.load(fileName))
		return false;

	BXmlNode* html = xmldoc.node("html");
	if (!html)
		return false;

	if (!setHtml(html))
		return false;

	if (member.fileName != fileName)
	{
		member.fileName = fileName;
		if (this->checks(Signal_FileNameChanged))
			this->emit(Signal_FileNameChanged, fileName);
	}

	return true;
}
bool BHtmlWidget::save(const BString& fileName) const
{
	BFile file(fileName);
	if (!file.open(IO_Write))
		return false;

	BXmlDocument document;
	if (member.htmlNode)
	{
		document.addNode(member.htmlNode);
	}
	else
	{
		document.addNode(member.bodyItem);
	}
	return document.write(file);
}
const BString& BHtmlWidget::fileName() const
{
	return member.fileName;
}

bool BHtmlWidget::read(const BStream& stream)
{
	BXmlDocument xmldoc;
	if (!xmldoc.read(stream))
		return false;

	BXmlNode* html = xmldoc.node("html");
	if (!html)
		return false;

	return setHtml(html);
}
bool BHtmlWidget::write(BStream& stream) const
{
	BXmlDocument document;
	if (member.htmlNode)
	{
		document.addNode(member.htmlNode);
	}
	else
	{
		document.addNode(member.bodyItem);
	}
	return document.write(stream);
}

bool BHtmlWidget::read(const BString& text)
{
	BXmlDocument xmldoc;
	if (!xmldoc.read(text))
		return false;

	BXmlNode* html = xmldoc.node("html");
	if (!html)
		return false;

	return setHtml(html);
}
bool BHtmlWidget::write(BString& text)
{
	BXmlDocument document;
	if (member.htmlNode)
	{
		document.addNode(member.htmlNode);
	}
	else
	{
		document.addNode(member.bodyItem);
	}
	return document.write(text);
}

void BHtmlWidget::setEditable(bool editable)
{
	if (member.editable != editable)
	{
		member.editable = editable;
		member.dirty = true;
		this->emit(Signal_Editable, editable);
		this->fresh();
	}
}
bool BHtmlWidget::editable() const
{
	return member.editable;
}

void BHtmlWidget::setAutoTitle(bool autoTitle)
{
	if (member.autoTitle != autoTitle)
	{
		member.autoTitle = autoTitle;
		member.dirty = true;
		this->emit(Signal_Changed);
		this->fresh();
	}
}
bool BHtmlWidget::autoTitle() const
{
	return member.autoTitle;
}

void BHtmlWidget::setSelectMode(SelectMode selectMode)
{
	if (member.selectMode != selectMode)
	{
		member.selectMode = selectMode;
		this->clearSelection();
	}
}
SelectMode BHtmlWidget::selectMode() const
{
	return member.selectMode;
}

bool BHtmlWidget::setItemSelected(BHtmlItem* item, bool selected)
{
	if (!item)
		return false;
	if (!item || item_member(item)->html != this)
		return false;
	if (!member.selectedItems.contain(item))
	{
		member.selectedItems.append(item);
		if (item)
		{
			item_member(item)->inputIndex = -1;
			item_member(item)->inputCount = 0;
			member.pressedIndex = 0;
			member.hoverIndex = 0;
		}
		emit(Signal_ItemSelected, item);
		this->fresh();
		return true;
	}
	return false;
}
bool BHtmlWidget::clearSelection()
{
	if (member.selectedItems.empty())
		return false;
	while (BHtmlItem* item = member.selectedItems.last())
	{
		member.selectedItems -= item;
		item_member(item)->selected = false;
		emit(Signal_ItemSelected, item);
	}
	emit(Signal_SelectionChanged, member.selectedItems.size());
	this->fresh();
	return true;
}

bool BHtmlWidget::removeItem(BHtmlItem* item)
{
	if (!item)
		return false;
	if (item_member(item)->html == this)
	{
		if (BHtmlItem* parent = item->parent())
		{
			if (member.selectedItems.remove(item))
			{
				member.hoveredItem = 0;
				item_member(item)->selected = false;
				this->emit(Signal_ItemSelected, item);
			}
			parent->removeChild(item);
			return true;
		}
		if (member.bodyItem == item)
		{
			return setBody(0);
		}
	}
	return false;
}
bool BHtmlWidget::clearItems()
{
	member.htmlNode = 0;
	if (member.fileName.size())
	{
		member.fileName.clear();
		if (this->checks(Signal_FileNameChanged))
			this->emit(Signal_FileNameChanged);
	}
	if (member.headNode)
	{
		member.disconnect(member.headNode);
		member.headNode = 0;
	}
	if (member.bodyItem)
	{
		member.disconnect(member.bodyItem);
		member.bodyItem = 0;
	}
	if (member.selectedItems.size())
	{
		while (BHtmlItem* item = member.selectedItems.last())
		{
			BHolder<BHtmlItem> holder(item);
			member.selectedItems -= item;
			item_member(item)->selected = false;
			emit(Signal_ItemSelected, item);
		}
		emit(Signal_SelectionChanged, member.selectedItems.size());
	}
	if (member.hoveredItem)
	{
		member.hoveredItem = 0;
		emit(Signal_ItemHovered, 0);
	}
	member.dirty = true;
	this->fresh();
	return true;
}
bool BHtmlWidget::empty() const
{
	return member.htmlNode.empty();
}

int BHtmlWidget::selectedItemCount() const
{
	return member.selectedItems.size();
}
BHtmlItem* BHtmlWidget::selectedItem(int index)
{
	return member.selectedItems(index);
}
const BHtmlItem* BHtmlWidget::selectedItem(int index) const
{
	return member.selectedItems(index);
}

bool BHtmlWidget::setSelection(BHtmlItem* item)
{
	bool selectionChanged = false;
	for (int i = 0; i < member.selectedItems.size(); i++)
	{
		BHtmlItem* selectedItem = member.selectedItems[i];
		if (item != selectedItem)
		{
			item_member(selectedItem)->selected = false;
			item_member(selectedItem)->inputIndex = 0;
			item_member(selectedItem)->inputCount = 0;
			member.selectedItems.remove(i--);
			emit(Signal_ItemSelected, selectedItem);
			selectionChanged = true;
		}
	}
	if (item && !member.selectedItems.contain(item))
	{
		item_member(item)->selected = true;
		item_member(item)->inputIndex = 0;
		item_member(item)->inputCount = 0;
		member.selectedItems.append(item);
		emit(Signal_ItemSelected, item);
		selectionChanged = true;
	}
	if (selectionChanged)
	{
		emit(Signal_SelectionChanged, member.selectedItems.size());
		this->fresh();
		return true;
	}
	return false;
}
bool BHtmlWidget::setSelection(const BHtmlItemArray& selection)
{
	bool selectionChanged = false;
	for (int i = 0; i < member.selectedItems.size(); i++)
	{
		BHtmlItem* item = member.selectedItems[i];
		if (!selection.contain(item))
		{
			item_member(item)->selected = false;
			member.selectedItems.remove(i--);
			emit(Signal_ItemSelected, item);
			selectionChanged = true;
		}
	}
	for (int i = 0; i < selection.size(); i++)
	{
		BHtmlItem* item = selection[i];
		if (!member.selectedItems.contain(item))
		{
			item_member(item)->selected = true;
			member.selectedItems.append(item);
			emit(Signal_ItemSelected, item);
			selectionChanged = true;
		}
	}
	member.selectedItems = selection;
	if (selectionChanged)
	{
		emit(Signal_SelectionChanged, member.selectedItems.size());
		this->fresh();
		return true;
	}
	return false;
}
const BHtmlItemArray& BHtmlWidget::selection() const
{
	return member.selectedItems;
}
BString BHtmlWidget::selectedText() const
{
	BString text;
	if (member.selectedItems.size() == 1)
	{
		BHtmlItem* item = member.selectedItems[0];
		item_member(item)->selection(text);
	}
	else if (member.selectedItems.size() > 1)
	{
		for (int i = 0; i < member.selectedItems.size(); i++)
		{
			BHtmlItem* item = member.selectedItems[i];
			item_member(item)->selection(text);
		}
	}
	return text;
}

bool BHtmlWidget::itemVisual(BHtmlItem* item) const
{
	return member.visualItems.contain(item);
}
bool BHtmlWidget::scrollToItem(BHtmlItem* item, Align align)
{
	if (!item || item_member(item)->html != this)
		return false;
	if (member.dirty)
	{
		this->flush();
	}
	BRect crect = this->centerRect();
	BRect area = this->area();
	BRect rect = item_member(item)->rect + area.pos();
	BSize size = crect.wrap(rect.size());
	BRect rect1 = crect.align(align, size);
	area.move(0, rect1.top() - rect.top());
	this->setArea(area);
	return true;
}

bool BHtmlWidget::setHtml(BXmlNode* html)
{
	if (member.htmlNode != html)
	{
		this->clearItems();
		member.htmlNode = html;
		member.headNode = html->child("head");
		BXmlNode* bodyNode = html->child("body");
		if (!bodyNode)
			bodyNode = html->addChild("body");

		BHtmlItem* bodyItem = new BHtmlItem(bodyNode);
		html->replaceChild(bodyNode, bodyItem);
		member.bodyItem = bodyItem;
		item_member(bodyItem)->attach(this);
		member.connect(member.bodyItem, Signal_Changed, &member_BHtmlWidget::slotBodyChanged);
		member.connect(member.headNode, Signal_Changed, &member_BHtmlWidget::slotHeadChanged);

		member.dirty = true;
		member.dirtyHead = true;
		member.dirtyResource = true;
		member.dirtyStyle = true;
		this->emit(Signal_Dirty);
		this->fresh();
		return true;
	}
	return false;
}
const BXmlNode* BHtmlWidget::html() const
{
	return member.htmlNode;
}
BXmlNode* BHtmlWidget::html()
{
	return member.htmlNode;
}

bool BHtmlWidget::setHead(BXmlNode* headNode)
{
	if (member.headNode != headNode)
	{
		if (BXmlNode* head = member.headNode)
		{
			if (member.htmlNode)
				member.htmlNode->removeChild(head);
			member.disconnect(head, Signal_Changed);
		}
		member.headNode = headNode;
		if (BXmlNode* head = member.headNode)
		{
			if (member.htmlNode)
				member.htmlNode->addChild(head);
			member.connect(head, Signal_Changed, &member_BHtmlWidget::slotHeadChanged);
		}
		member.dirtyHead = true;
		member.dirtyResource = true;
		this->fresh();
		return true;
	}
	return false;
}
const BXmlNode* BHtmlWidget::head() const
{
	return member.headNode;
}
BXmlNode* BHtmlWidget::head()
{
	return member.headNode;
}

bool BHtmlWidget::setBody(BHtmlItem* bodyItem)
{
	if (member.bodyItem != bodyItem)
	{
		if (BHtmlItem* body = member.bodyItem)
		{
			item_member(body)->detach(this);
			member.disconnect(body, Signal_Changed);
			if (member.htmlNode)
				member.htmlNode->removeChild(body);
		}
		member.bodyItem = bodyItem;
		if (BHtmlItem* body = member.bodyItem)
		{
			item_member(body)->attach(this);
			member.connect(body, Signal_Changed, &member_BHtmlWidget::slotBodyChanged);
			if (member.htmlNode)
				member.htmlNode->addChild(body);
		}
		member.dirtyHead = true;
		member.dirtyResource = true;
		member.dirtyStyle = true;
		this->fresh();
		return true;
	}
	return false;
}
const BHtmlItem* BHtmlWidget::body() const
{
	return member.bodyItem;
}
BHtmlItem* BHtmlWidget::body()
{
	return member.bodyItem;
}

BHtmlItem* BHtmlWidget::itemAt(const BPoint& point)
{
	BPoint offset = this->area().pos();
	BHtmlItem* item = member.findItem(point - offset);
	return item;
}
const BHtmlItem* BHtmlWidget::itemAt(const BPoint& point) const
{
	BPoint offset = this->area().pos();
	BHtmlItem* item = member.findItem(point - offset);
	return item;
}

BHtmlItem* BHtmlWidget::locate(const BString& desc)
{
	return (BHtmlItem*)member.bodyItem->find(desc);
}
const BHtmlItem* BHtmlWidget::locate(const BString& desc) const
{
	return (const BHtmlItem*)member.bodyItem->find(desc);
}

bool BHtmlWidget::input(const BString& text, const BValue& value)
{
	if (text == "hovered-item")
	{
		BHtmlItem* item = value;
		if (member.hoveredItem != item)
		{
			member.hoveredItem = item;
			CursorType cursor = Cursor_Arrow;
			if (member.hoveredItem)
			{
				if (member.editable && item == member.selectedItems.first())
					cursor = Cursor_Ibeam;
				if (!member.editable && item->name() == 'a')
					cursor = Cursor_Hand;
			}
			this->setCursor(cursor);
			this->emit(Signal_ItemHovered, item);
		}
		return true;
	}
	return BScrollArea::input(text, value);
}
bool BHtmlWidget::query(const BString& text, BValue& value) const
{
	if (text == "hovered-item")
	{
		value = member.hoveredItem;
		return true;
	}
	if (text == "selected-items")
	{
		BHtmlItemArray& items = value.fill<BHtmlItemArray>();
		items = member.selectedItems;
		return true;
	}
	return BScrollArea::query(text, value);
}
void BHtmlWidget::scrolling(Orientation orientation)
{
	this->fresh();
	BScrollArea::scrolling(orientation);
}

void BHtmlWidget::updateEvent(const BEvent& event)
{
	if (this->focused() && member.editable && member.selectedItems.size() == 1)
	{
		BHtmlItem* item = member.selectedItems.first();
		member_BHtmlItem* input = item_member(item);
		bool blinkShown = (input->inputIndex >= 0) && (input->inputCount == 0);
		if (blinkShown)
		{
			if (member.blinkTime > 0.0)
			{
				BReal now = event.now();
				BReal time = now - member.blinkTick;
				blinkShown = time <= (member.blinkTime * 0.5);
				if (time > member.blinkTime)
					member.blinkTick = now;
			}
		}
		if (member.blinkShown != blinkShown)
		{
			member.blinkShown = blinkShown;
			this->fresh();
		}
	}
}
void BHtmlWidget::resizeEvent(const BEvent& event)
{
	BScrollArea::resizeEvent(event);
	member.dirty = true;
}

void BHtmlWidget::styleEvent(const BEvent& event)
{
	BScrollArea::styleEvent(event);
	member.dirtyStyle = true;
	member.dirty = true;
}
void BHtmlWidget::freshEvent(const BEvent& event)
{
	if (member.dirtyHead)
	{
		member.dirtyHead = false;
		AutoWorkPath autopath(member.fileName.path());
		member.initStyle();
		member.initHead();
		member.dirty = true;
	}
	if (member.dirtyResource)
	{
		member.dirtyResource = false;
		AutoWorkPath autopath(member.fileName.path());
		member.loadResource(member.bodyItem);
		member.dirty = true;
	}
	if (member.dirtyStyle)
	{
		member.dirtyStyle = false;
		member.freshStyle();
		member.dirty = true;
	}
	if (member.dirty)
	{
		member.dirty = false;
		member.freshPageArea();
	}
	BScrollArea::freshEvent(event);
}
void BHtmlWidget::paintEvent(const BEvent& event)
{
	BScrollArea::paintEvent(event);
	BPainter painter(this);

	if (BHtmlItem* bodyItem = member.bodyItem)
	{
		member.paintItem(bodyItem, painter);
	}

	for (int i = 0; i < member.floatItems.size(); i++)
	{
		BHtmlItem* item = member.floatItems[i];
		member.paintFloatItem(item, painter);
	}

	if (member.editable && member.blinkShown && member.selectedItems.size() == 1)
	{
		painter.setLineWidth(1);
		painter.setColor(Color_Indicator);
		BLine2 line = member.inputLine();
		painter.drawLine(line.begin(), line.end());
	}
}

void BHtmlWidget::focusEvent(const BEvent& event)
{
	if (member.editable)
	{
		if (this->focused())
		{
			member.blinkShown = true;
			this->fresh();
		}
		else
		{
			member.blinkShown = false;
			if (member.editing)
			{
				member.editing = false;
				this->fresh();
				emit(Signal_EditFinished);
			}
		}
	}
	BScrollArea::focusEvent(event);
}
void BHtmlWidget::inputEvent(const BEvent& event)
{
	if (member.editable && member.selectedItems.size() == 1)
	{
		BHtmlItem* item = member.selectedItems.first();
		BCode code = event.value();
		member_BHtmlItem& block = *item_member(item);
		bool edited = block.removeSelection();
		if (item_member(item)->insert(code))
		{
			edited = true;
		}
		if (edited)
		{
			member.itemTextEdited(item);
			BLine2 line = member.inputLine();
			event.accept(line.end());
		}
	}
	BScrollArea::inputEvent(event);
}

void BHtmlWidget::keyPressEvent(const BKeyEvent& keyEvent)
{
	if (member.selectedItems.size() == 1)
	{
		BHtmlItem* focusedItem = member.selectedItems.first();
		member_BHtmlItem& itemem = *item_member(focusedItem);
		if (keyEvent.keyState(Key_Ctrl))
		{
			if (keyEvent.key() == Key_C)
			{
				BString text;
				itemem.selection(text);
				BSystem::SetClippedText(text);
				keyEvent.accept(true);
			}
			else if (keyEvent.key() == Key_A)
			{
				itemem.inputIndex = 0;
				itemem.inputCount = itemem.cells.size();
				member.blinkShown = false;
				this->fresh();
				keyEvent.accept(true);
			}
			else if (member.editable)
			{
				if (keyEvent.key() == Key_V)
				{
					itemem.removeSelection();
					BString text;
					bool ret = BSystem::GetClippedText(text);
					if (itemem.insert(text))
					{
						member.itemTextEdited(focusedItem);
					}
					keyEvent.accept(true);
				}
				if (keyEvent.key() == Key_X)
				{
					BString text;
					itemem.selection(text);
					BSystem::SetClippedText(text);
					if (itemem.removeSelection())
					{
						member.itemTextEdited(focusedItem);
					}
					keyEvent.accept(true);
				}
			}
		}
		if (member.editable)
		{
			switch (keyEvent.key())
			{
			case Key_Left:
			{
				if (keyEvent.keyState(Key_Ctrl))
				{
					itemem.seekPrevWord();
					this->fresh();
				}
				if (itemem.inputCount)
				{
					itemem.inputCount = 0;
					this->fresh();
				}
				else if (itemem.inputIndex > 0)
				{
					itemem.inputIndex--;
					this->fresh();
				}
				member.blinkTick = keyEvent.now() + (BReal)0.5;
				keyEvent.accept(true);
				break;
			}
			case Key_Right:
			{
				if (keyEvent.keyState(Key_Ctrl))
				{
					itemem.seekNextWord();
					this->fresh();
				}
				if (itemem.inputCount)
				{
					itemem.inputIndex += itemem.inputCount;
					itemem.inputCount = 0;
					this->fresh();
				}
				else if (itemem.inputIndex < itemem.cells.size())
				{
					itemem.inputIndex++;
					this->fresh();
				}
				member.blinkTick = keyEvent.now() + (BReal)0.5;
				keyEvent.accept(true);
				break;
			}
			case Key_Up:
			{
				keyEvent.accept(true);
				break;
			}
			case Key_Down:
			{
				keyEvent.accept(true);
				break;
			}
			case Key_Home:
			{
				itemem.seekHead();
				keyEvent.accept(true);
				break;
			}
			case Key_End:
			{
				itemem.seekTail();
				keyEvent.accept(true);
				break;
			}
			case Key_Tab:
			{
				itemem.insert(BCode('\t'));
				member.itemTextEdited(focusedItem);
				keyEvent.accept(true);
				break;
			}
			case Key_Enter:
			{
				if (focusedItem->name() == "pre")
				{
					itemem.insert(BCode('\n'));
					member.itemTextEdited(focusedItem);
				}
				else if (focusedItem->display() >= BHtmlItem::Display_Inline)
				{
					if (BHtmlItem* parentItem = focusedItem->parent())
					{
						BHtmlItem* brItem = new BHtmlItem("br");
						parentItem->insertChild(focusedItem->index() + 1, brItem);

						BHtmlItem* nextItem = new BHtmlItem(focusedItem->name());
						BString nextText;
						itemem.substr(nextText, itemem.inputIndex, itemem.cells.size());
						nextItem->setText(nextText);
						itemem.remove(itemem.inputIndex, itemem.cells.size());
						parentItem->insertChild(focusedItem->index() + 2, nextItem);

						member.itemTextEdited(focusedItem);
						this->setSelection(nextItem);
					}
				}
				else if (focusedItem->display() > BHtmlItem::Display_None)
				{
					BString nextText;
					itemem.substr(nextText, itemem.inputIndex, itemem.cells.size());
					itemem.remove(itemem.inputIndex, itemem.cells.size());
					BHtmlItem* nextItem = focusedItem->insertText(0, nextText);

					BHtmlItem* brItem = new BHtmlItem("br");
					focusedItem->insertChild(0, brItem);

					member.itemTextEdited(focusedItem);
					this->setSelection(nextItem);
				}
				keyEvent.accept(true);
				break;
			}
			case Key_Delete:
			{
				if (itemem.removeSelection())
				{
					member.itemTextEdited(focusedItem);
				}
				else if (itemem.remove(itemem.inputIndex))
				{
					member.itemTextEdited(focusedItem);
				}
				keyEvent.accept(true);
				break;
			}
			case Key_Back:
			{
				if (itemem.inputCount)
				{
					if (itemem.removeSelection())
					{
						member.itemTextEdited(focusedItem);
					}
				}
				else if (itemem.inputIndex > 0)
				{
					itemem.inputIndex--;
					if (itemem.remove(itemem.inputIndex))
					{
						member.itemTextEdited(focusedItem);
					}
				}
				keyEvent.accept(true);
				break;
			}
			default:
				break;
			}
		}
	}
	BScrollArea::keyPressEvent(keyEvent);
}
void BHtmlWidget::keyReleaseEvent(const BKeyEvent& keyEvent)
{
	BScrollArea::keyReleaseEvent(keyEvent);
}

void BHtmlWidget::mouseEnterEvent(const BMouseEvent& mouseEvent)
{
	if (member.hoveredItem)
	{
		member.hoveredItem = 0;
		this->fresh();
	}
	this->setCursor(Cursor_Arrow);
	BScrollArea::mouseEnterEvent(mouseEvent);
}
void BHtmlWidget::mouseLeaveEvent(const BMouseEvent& mouseEvent)
{
	if (member.hoveredItem)
	{
		member.hoveredItem = 0;
		this->fresh();
	}
	this->setCursor(Cursor_Arrow);
	BScrollArea::mouseLeaveEvent(mouseEvent);
}

void BHtmlWidget::mousePressEvent(const BMouseEvent& mouseEvent)
{
	const BPoint& pos = mouseEvent.pos();
	if (mouseEvent.button() == Button_Left)
	{
		if (mouseEvent.keyState(Key_Ctrl))
		{
			BHtmlItem* hoveredItem = member.hoveredItem;
			if (member.selectedItems.contain(hoveredItem))
			{
				item_member(hoveredItem)->selectWord();
			}
		}
		else if (mouseEvent.keyState(Key_Shift))
		{
			member.selectItems();
		}
		else
		{
			if (this->rect(Part_Left).contain(pos))
			{
				this->setSelection(member.hoveredItem);
				if (BHtmlItem* hoveredItem = member.hoveredItem)
				{
					item_member(hoveredItem)->inputIndex = 0;
					item_member(hoveredItem)->inputCount = item_member(hoveredItem)->cells.size();
				}
			}
			else
			{
				BHtmlItem* hoveredItem = member.hoveredItem;
				this->setSelection(hoveredItem);
				if (hoveredItem)
				{
					item_member(hoveredItem)->inputIndex = member.hoverIndex;
					item_member(hoveredItem)->inputCount = 0;
				}
				member.blinkShown = true;
				member.blinkTick = mouseEvent.time() + (BReal)0.5;
			}
			member.pressed = true;
			member.pressedItem = member.hoveredItem;
			member.pressedIndex = member.hoverIndex;
			if (this->checks(Signal_SelectionChanged))
				this->emit(Signal_SelectionChanged, this->selectedText());
		}
		this->fresh();
	}
	BScrollArea::mousePressEvent(mouseEvent);
}
void BHtmlWidget::mouseReleaseEvent(const BMouseEvent& mouseEvent)
{
	if (mouseEvent.button() == Button_Left)
	{
		member.pressed = false;
		member.pressPoint.reset();
	}
	BScrollArea::mouseReleaseEvent(mouseEvent);
}
void BHtmlWidget::mouseMoveEvent(const BMouseEvent& mouseEvent)
{
	const BPoint& pos = mouseEvent.pos();
	BPoint offset = this->area().pos();
	BHtmlItem* item = member.findItem(pos - offset);
	if (member.hoveredItem != item)
	{
		member.hoveredItem = item;
		this->emit(Signal_ItemHovered, item);
	}
	int hoverIndex = -1;
	if (member.hoveredItem)
	{
		hoverIndex = item_member(member.hoveredItem)->indexAt(pos - offset);
	}
	if (member.hoverIndex != hoverIndex)
	{
		member.hoverIndex = hoverIndex;
		this->fresh();
	}
	if (member.pressed)
	{
		BHtmlItem* hoveredItem = member.hoveredItem;
		if (hoveredItem && item_member(hoveredItem)->selected)
		{
			item_member(hoveredItem)->inputIndex = bMin(member.pressedIndex, member.hoverIndex);
			item_member(hoveredItem)->inputCount = abs(member.pressedIndex - member.hoverIndex);
			this->fresh();
		}
	}
	else if (mouseEvent.button() == Button_None && this->focusable())
	{
		CursorType cursor = Cursor_Arrow;
		if (BHtmlItem* hoveredItem = member.hoveredItem)
		{
			if (item_member(hoveredItem)->textRect.contain(pos - offset))
			{
				cursor = Cursor_Ibeam;
			}
			if (!member.editable && item->name() == 'a')
			{
				cursor = Cursor_Hand;
			}
		}
		this->setCursor(cursor);
	}
	BScrollArea::mouseMoveEvent(mouseEvent);
}

void BHtmlWidget::mouseClickEvent(const BMouseEvent& mouseEvent)
{
	BScrollArea::mouseClickEvent(mouseEvent);
	const BPoint& pos = mouseEvent.pos();
	if (mouseEvent.button() == Button_Left)
	{
		if (!member.editable && member.hoveredItem && member.hoveredItem->name() == 'a')
		{
			const BString& href = member.hoveredItem->attrib("href");
			if (href.beginWith('#'))
			{
				BString desc(":id=\"");
				desc.append(href, 1);
				desc.append('\"');
				if (BHtmlItem* item = this->locate(desc))
				{
					const BRect& crect = this->centerRect();
					BRect area = this->area();
					BRect rect = item_member(item)->rect + area.pos();
					BSize size = crect.wrap(rect.size());
					BRect rect1 = crect.align(Align_Center, size);
					area.move(0, rect1.top() - rect.top());
					this->setArea(area);
					this->setItemSelected(item);
				}
				mouseEvent.accept();
			}
		}
		else if (this->centerRect().contain(pos))
		{
			if (member.selectMode & Select_Single)
			{
				if (BHtmlItem* item = member.hoveredItem)
				{
					bool selectionChanged = false;
					for (int i = 0; i < member.selectedItems.size(); i++)
					{
						if (member.selectedItems[i] != item)
						{
							BHtmlItem* temp = member.selectedItems[i];
							member.selectedItems.remove(i--);
							item_member(temp)->selected = false;
							emit(Signal_ItemSelected, temp);
							selectionChanged = true;
						}
					}
					if (member.selectedItems.empty())
					{
						member.selectedItems.append(item);
						item_member(item)->selected = true;
						emit(Signal_ItemSelected, item);
						selectionChanged = true;
					}
					if (selectionChanged)
					{
						emit(Signal_SelectionChanged, member.selectedItems.size());
						this->fresh();
					}
				}
				else
				{
					clearSelection();
				}
			}
			if (member.selectMode & Select_Multiple)
			{
				BHtmlItem* item = member.hoveredItem;
				if (item == 0)
				{
					if (!mouseEvent.keyState(Key_Ctrl) && !mouseEvent.keyState(Key_Shift))
					{
						clearSelection();
					}
				}
				else if (member.selectMode & Select_Multiple && mouseEvent.keyState(Key_Ctrl))
				{
					bool selected = !item_member(item)->selected;
					setItemSelected(item, selected);
				}
				else
				{
					bool selectionChanged = false;
					for (int i = 0; i < member.selectedItems.size(); i++)
					{
						if (member.selectedItems[i] != item)
						{
							BHtmlItem* temp = member.selectedItems[i];
							member.selectedItems.remove(i--);
							item_member(temp)->selected = false;
							emit(Signal_ItemSelected, temp);
							selectionChanged = true;
						}
					}
					if (item && member.selectedItems.empty())
					{
						member.selectedItems.append(item);
						item_member(item)->selected = true;
						emit(Signal_ItemSelected, item);
						selectionChanged = true;
					}
					if (selectionChanged)
					{
						emit(Signal_SelectionChanged, member.selectedItems.size());
						this->fresh();
					}
				}
			}
		}
		emit(Signal_ItemClicked, member.hoveredItem);
		mouseEvent.accept();
	}
	if (mouseEvent.button() == Button_Right)
	{
		emit(Signal_ItemRightClicked, member.hoveredItem);
		mouseEvent.accept();
	}
}
void BHtmlWidget::mouseDoubleClickEvent(const BMouseEvent& mouseEvent)
{
	if (mouseEvent.button() == Button_Left)
	{
		if (BHtmlItem* hoveredItem = member.hoveredItem)
		{
			emit(Signal_ItemDoubleClicked, hoveredItem);
			if (item_member(hoveredItem)->selectWord())
			{
				member.pressedItem = hoveredItem;
				member.pressedIndex = item_member(hoveredItem)->inputIndex;
				this->fresh();
			}
		}
	}
	BScrollArea::mouseDoubleClickEvent(mouseEvent);
}

